﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SC.Net
{
    //**********************
    //**编写人:付利军
    //**编写时间:2011-11-20
    //**说明:Tcp服务端类
    //**********************
    public class TcpServer
    {
        #region 属性

        //最大字节长度
        const int REVLEN = 2048;

        //监听套接字
        Socket _listener = null;

        //最大连接数
        int _maxClientCount = 0;

        public int MaxClientCount
        {
            get { return _maxClientCount; }
            set { _maxClientCount = value; }
        }

        //主机IP
        IPAddress _ip = null;

        //本地端口
        int _port = 0;

        //线程
        System.Threading.Thread m_thread;

        //是否打开
        bool _isOpen = false;

        /// <summary>
        /// 当前服务状态
        /// </summary>
        public bool IsOpen
        {
            get { return _isOpen; }
        }

        //关闭连接
        bool _shutdown = true;

        public bool Shutdown
        {
            set { _shutdown = value; }
        }

        //控制监听线程互斥
        private ManualResetEvent m_evtListen = new ManualResetEvent(false);

        #endregion

        #region 委托事件

        public delegate void TcpServerRevDataEvent(object sender, TcpServerRevDataEventArgs e);

        /// <summary>
        /// 接收数据事件
        /// </summary>
        public event TcpServerRevDataEvent ReciveData;

        /// <summary>
        /// 错误事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void TcpServerErrorEvent(object sender, TcpServerErrorEventArgs e);

        public event TcpServerErrorEvent Error;

        /// <summary>
        /// 连接失效委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void TcpServerDisConnectEvent(object sender, TcpSeverDisConnectEventArgs e);

        public event TcpServerDisConnectEvent DisConnect;

        #endregion


        /// <summary>
        /// 关闭监听
        /// </summary>
        public void CloseListen()
        {
            _shutdown = true;
            _isOpen = false;
            m_evtListen.Set();
        }

        /// <summary>
        /// 启动监听
        /// </summary>
        /// <param name="aIP">本机IP</param>
        /// <param name="aPort">端口</param>
        public void StartListen(string aIP, int aPort)
        {
            if (IsOpen == false)
            {
                try
                {
                    //获取本地IP
                    _ip = IPAddress.Parse(aIP);
                    _port = aPort;//端口
                    _shutdown = false; //服务设置为打开
                    m_evtListen = new ManualResetEvent(false);//互斥变量
                    m_thread = new Thread(new ThreadStart(ListenThread));//开始监听线程
                    m_thread.Start();  //启动监听线程
                }
                catch (Exception ex)
                {
                    Error(this,new TcpServerErrorEventArgs(ex,null, ErrPosition.ServerStar));
                }
            }
        }

        //监听线程
        void ListenThread()
        {
            //绑定本机IP,端口
            IPEndPoint localEndPoint = new IPEndPoint(_ip, _port);

            //初始化监听线程
            _listener = new Socket(AddressFamily.InterNetwork,
                                    SocketType.Stream,
                                    ProtocolType.Tcp);

            //将套接字和本地终结点绑定，监听端口
            try
            {
                _listener.Bind(localEndPoint);
                //设置最大监听数量
                _listener.Listen(_maxClientCount);
                //将当前状态设置为打开
                _isOpen = true;
                //将关闭设置为false
                _shutdown = false;
                //如果没有关闭则循环
                while (!_shutdown)
                {
                    m_evtListen.Reset();
                    _listener.BeginAccept( new AsyncCallback(AcceptCallback), _listener);

                    //等待建立连接后继续
                    m_evtListen.WaitOne();
                }

                //停止监听后关闭连接并释放
                _listener.Close();
                _listener = null;

            }
            catch (Exception ex)
            {
                if (Error != null)
                    Error(this, new TcpServerErrorEventArgs(ex,null, ErrPosition.StarListen));
            }
            finally
            {

            }

        }

        //接受信息回调
        private void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                if (_listener != null)
                {
                    //声明数据缓存
                    byte[] bytes = new byte[REVLEN];//接收数据缓存
                    Socket handler = _listener.EndAccept(ar);  //获得连接socket句柄

                    //将连接的socket句柄的接收的数据传入ReadCallBack
                    object[] objs = new object[2];
                    objs[0] = handler;
                    objs[1] = bytes;

                    //接收数据
                    handler.BeginReceive(bytes,  //接收数据缓存
                                        0,   //缓存接收数据的位置
                                        REVLEN, //接收的字节数
                                        0,  //
                                        new AsyncCallback(ReadCallBack), objs);

                    m_evtListen.Set();//连接建立之后,停止阻塞,继续执行监听线程  
                }                 
            }
            catch (Exception ex)
            {
                if (Error != null)
                    Error(this, new TcpServerErrorEventArgs(ex,null, ErrPosition.AcceptCallback));
            }
        }

        //读数据
        private void ReadCallBack(IAsyncResult ar)
        {
            object[] objs = (object[])ar.AsyncState;
            Socket socket = (Socket)objs[0];
            byte[] data = (byte[])objs[1];

            try
            {
                int bytesRead = socket.EndReceive(ar);//结束异步读取数据
                if (bytesRead > 0)
                {
                    if (ReciveData != null)
                        ReciveData(this, new TcpServerRevDataEventArgs(data, socket));//收到数据引发读数据事件

                    object[] objsr = new object[2];
                    objsr[0] = socket;

                    byte[] bytes = new byte[REVLEN]; 
                    objsr[1] = bytes;


                    socket.BeginReceive(bytes,  //接收数据缓存
                                        0,   //缓存接收数据的位置
                                        REVLEN, //接收的字节数
                                        0,  //
                                        new AsyncCallback(ReadCallBack), objsr);
                }
                else
                {
                    //小于零执行断开连接事件
                    if (DisConnect != null)
                        DisConnect(this,new TcpSeverDisConnectEventArgs("连接失效",socket));
                }
            }
            catch (Exception ex)
            {
                if (Error != null)
                    Error(this, new TcpServerErrorEventArgs(ex,socket,ErrPosition.ReadCallBack));
            }
        }
        
        //发送信息
        public void Send(byte[] byteData, int len, Socket handler)
        {
            try
            {
                handler.BeginSend(byteData //发送数据缓存
                                , 0  //发送数据起始位置
                                , len // 数据长度
                                , 0 //套接字标志
                                , new AsyncCallback(SendCallback)
                                , handler);

            }
            catch (Exception ex)
            {

            }
        }

        //发送回调
        private void SendCallback(IAsyncResult ar)
        {
            Socket handler = (Socket)ar.AsyncState;
            try
            {
                int bytesSent = handler.EndSend(ar);
            }
            catch (Exception ex)
            {
                if (Error != null)
                    Error(this, new TcpServerErrorEventArgs(ex,handler, ErrPosition.SendCallback));
            }
        }
    }
}
